home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1995 #5 & #6
/
Amiga Plus CD - 1995 - No. 5 and 6.iso
/
pd
/
daten
/
astrolog
/
src
/
xgeneral.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-11
|
25KB
|
1,064 lines
/* -*- C -*-
** Astrolog (Version 4.40) File: xgeneral.c
**
** IMPORTANT NOTICE: The graphics database and chart display routines
** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
** (astara@u.washington.edu). Permission is granted to freely use and
** distribute these routines provided one doesn't sell, restrict, or
** profit from them in any way. Modification is allowed provided these
** notices remain with any altered or edited versions of the program.
**
** The main planetary calculation routines used in this program have
** been Copyrighted and the core of this program is basically a
** conversion to C of the routines created by James Neely as listed in
** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
** available from Matrix Software. The copyright gives us permission to
** use the routines for personal use but not to sell them or profit from
** them in any way.
**
** The PostScript code within the core graphics routines are programmed
** and Copyright (C) 1992-1993 by Brian D. Willoughby
** (brianw@sounds.wa.com). Conditions are identical to those above.
**
** The extended accurate ephemeris databases and formulas are from the
** calculation routines in the program "Placalc" and are programmed and
** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
** (alois@azur.ch). The use of that source code is subject to
** regulations made by Astrodienst Zurich, and the code is not in the
** public domain. This copyright notice must not be changed or removed
** by any user of this program.
**
** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
** X Window graphics initially programmed 10/23-29/1991.
** PostScript graphics initially programmed 11/29-30/1992.
** Last code change made 1/29/1995.
*/
/* $VER: $Id: xgeneral.c,v 1.4 1995/07/02 22:22:54 tf Exp $ */
#include "astrolog.h"
#ifdef GRAPH
/*
******************************************************************************
** Core Graphic Procedures.
******************************************************************************
*/
/* Set the current color to use in drawing on the screen or bitmap array. */
void DrawColor(col)
KI col;
{
if (gi.fFile)
{
#ifdef PS
if (gs.fPS) {
if (gi.kiCur != col)
{
PsStrokeForce(); /* Render existing path with current color */
fprintf(gi.file, "%.2f %.2f %.2f c\n",
(real)RGBR(rgbbmp[col])/255.0, (real)RGBG(rgbbmp[col])/255.0,
(real)RGBB(rgbbmp[col])/255.0);
}
}
#endif
#ifdef META
if (gs.fMeta)
gi.kiLineDes = col;
#endif
}
#ifdef X11
else
XSetForeground(gi.disp, gi.gc, rgbind[col]);
#endif
#ifdef MSG
else
_setcolor(col);
#endif
#ifdef BGI
else
setcolor(col);
#endif
#ifdef AMIGA
else
{
/*printf("DrawColor(%d)\n",col);*/
/*SetAPen(gi.rp, rand()%16);*/
/*SetAPen(gi.rp, col);*/
AmigaSetPen(col);
}
#endif
gi.kiCur = col;
}
/* Set a single point on the screen. This is the most basic graphic function */
/* and is called by all the more complex routines. Based on what mode we are */
/* in, we either set a cell in the bitmap array or a pixel on the window. */
void DrawPoint(x, y)
int x, y;
{
if (gi.fFile)
{
if (gs.fBitmap)
{
/* Force the coordinates to be within the bounds of the bitmap array. */
if (x < 0) x = 0; else if (x >= gs.xWin) x = gs.xWin-1;
if (y < 0) y = 0; else if (y >= gs.yWin) y = gs.yWin-1;
if (gi.yBand)
{
y -= gi.yOffset;
if (y < 0 || y >= gi.yBand)
return;
}
BmSet(gi.bm, x, y, gi.kiCur);
}
#ifdef PS
else if (gs.fPS)
{
DrawColor(gi.kiCur);
PsLineCap(fTrue);
fprintf(gi.file, "%d %d d\n", x, y);
PsStroke(2);
}
#endif
#ifdef META
else
{
gi.kiFillDes = gi.kiCur;
MetaSelect();
MetaEllipse(x-gi.nPenWid/2, y-gi.nPenWid/2,
x+gi.nPenWid/2, y+gi.nPenWid/2);
}
#endif
}
#ifdef X11
else
XDrawPoint(gi.disp, gi.pmap, gi.gc, x, y);
#endif
#ifdef MSG
else
_setpixel(gi.xOffset + x, gi.yOffset + y);
#endif
#ifdef BGI
else
putpixel(gi.xOffset + x, gi.yOffset + y, gi.kiCur);
#endif
#ifdef AMIGA
else
{
/*
if (x < 0) x = 0; else if (x >= gs.xWin) x = gs.xWin-1;
if (y < 0) y = 0; else if (y >= gs.yWin) y = gs.yWin-1;
*/
WritePixel( gi.rp, (SHORT)(gi.xOffset + x), (SHORT)(gi.yOffset + y) );
}
#endif
}
/* Draw dot a little larger than just a single pixel at specified location. */
void DrawSpot(x, y)
int x, y;
{
#ifdef PS
if (gs.fPS)
{
PsLineWidth((int)(gi.rLineWid*3.0));
DrawPoint(x, y);
PsLineWidth((int)(gi.rLineWid/3.0));
return;
}
#endif
#ifdef META
if (gs.fMeta)
{
gi.kiFillDes = gi.kiCur;
MetaSelect();
MetaEllipse(x-gi.nPenWid, y-gi.nPenWid, x+gi.nPenWid, y+gi.nPenWid);
return;
}
#endif
{
int X,Y;
#ifdef AMIGA
X= x + gi.xOffset;
Y= y + gi.yOffset;
#else
X= x;
Y= y;
#endif
DrawPoint(X, Y);
DrawPoint(X, Y-1);
DrawPoint(X-1, Y);
DrawPoint(X+1, Y);
DrawPoint(X, Y+1);
}
}
/* Draw a filled in block, defined by the corners of its rectangle. */
void DrawBlock(x1, y1, x2, y2)
int x1, y1, x2, y2;
{
int x, y;
if (gi.fFile)
{
if (gs.fBitmap)
{
if (gi.yBand) {
y1 -= gi.yOffset; if (y1 < 0) y1 = 0;
y2 -= gi.yOffset; if (y2 > gi.yBand) y2 = gi.yBand-1;
}
for (y = y1; y <= y2; y++) /* For bitmap, we have to */
for (x = x1; x <= x2; x++) /* just fill in the array. */
BmSet(gi.bm, x, y, gi.kiCur);
}
#ifdef PS
else if (gs.fPS)
{
DrawColor(gi.kiCur);
fprintf(gi.file, "%d %d %d %d rf\n",
Max(x1-gi.nPenWid/4, 0), Max(y1-gi.nPenWid/4, 0),
x2-x1+gi.nPenWid/4, y2-y1+gi.nPenWid/4);
}
#endif
#ifdef META
else
{
gi.kiFillDes = gi.kiCur;
MetaSelect();
MetaRectangle(x1-gi.nPenWid/2, y1-gi.nPenWid/2, x2+gi.nPenWid/2, y2+gi.nPenWid/2);
}
#endif
}
#ifdef X11
else
XFillRectangle(gi.disp, gi.pmap, gi.gc, x1, y1, x2-x1, y2-y1);
#endif
#ifdef MSG
else
_rectangle(_GFILLINTERIOR, gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
#endif
#ifdef BGI
else {
setfillstyle(SOLID_FILL, gi.kiCur);
bar(gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
}
#endif
#ifdef AMIGA
else
{
int x_min, x_max, y_min, y_max;
if(x1<x2) { x_min= x1; x_max= x2; } else { x_min= x2; x_max= x1; }
if(y1<y2) { y_min= y1; y_max= y2; } else { y_min= y2; y_max= y1; }
x_min += gi.xOffset; y_min += gi.yOffset;
x_max += gi.xOffset; y_max += gi.yOffset;
RectFill( gi.rp, x_min,y_min, x_max,y_max );
}
#endif
}
/* Draw a rectangle on the screen with specified thickness. This is just */
/* like DrawBlock() except that we are only drawing the edges of the area. */
void DrawBox(x1, y1, x2, y2, xsiz, ysiz)
int x1, y1, x2, y2, xsiz, ysiz;
{
#ifdef META
if (gs.fMeta)
{
/* For thin boxes in metafiles, we can just output one rectangle record */
/* instead of drawing each side separately as we have to do otherwise. */
if (xsiz <= 1 && ysiz <= 1)
{
gi.kiFillDes = kNull; /* Specify a hollow fill brush. */
MetaSelect();
MetaRectangle(x1, y1, x2, y2);
return;
}
}
#endif /* META */
DrawBlock(x1, y1, x2, y1 + ysiz - 1);
DrawBlock(x1, y1 + ysiz, x1 + xsiz - 1, y2 - ysiz);
DrawBlock(x2 - xsiz + 1, y1 + ysiz, x2, y2 - ysiz);
DrawBlock(x1, y2 - ysiz + 1, x2, y2);
}
/* Clear and erase the graphics screen or bitmap contents. */
void DrawClearScreen()
{
#ifdef PS
if (gs.fPS)
{
/* For PostScript charts first output page orientation information. */
if (!gi.fEps)
{
if (gs.nOrient == 0)
gs.nOrient = (gs.xWin > gs.yWin) ? -1 : 1;
if (gs.nOrient < 0)
{
/* chartx and charty are reversed for Landscape mode. */
fprintf(gi.file, "%d %d translate\n",
((int)(gs.xInch*72.0+rRound) + gs.yWin)/2,
((int)(gs.yInch*72.0+rRound) + gs.xWin)/2);
fprintf(gi.file, "-90 rotate\n");
}
else
{
/* Most charts are in Portrait mode */
fprintf(gi.file, "%d %d translate\n",
((int)(gs.xInch*72.0+rRound) - gs.xWin)/2,
((int)(gs.yInch*72.0+rRound) + gs.yWin)/2);
}
} else
fprintf(gi.file, "0 %d translate\n", gs.yWin);
fprintf(gi.file, "1 -1 scale\n");
gs.nScale *= PSMUL; gs.xWin *= PSMUL; gs.yWin *= PSMUL; gi.nScale *= PSMUL;
fprintf(gi.file, "1 %d div dup scale\n", PSMUL);
}
#endif
#ifdef META
if (gs.fMeta)
MetaInit(); /* For metafiles first go write our header information. */
#endif
/* Don't actually erase the screen if the -Xj switch is in effect. */
if (gs.fJetTrail)
return;
#ifdef MSG
if (!gi.fFile)
_clearscreen(_GCLEARSCREEN);
#endif /* MSG */
#ifdef BGI
if (!gi.fFile)
clearviewport();
#endif
#ifdef AMIGA
if (!gi.fFile)
AmigaClearScreen();
#endif /* AMIGA */
DrawColor(gi.kiOff);
DrawBlock(0, 0, gs.xWin - 1, gs.yWin - 1); /* Clear bitmap screen. */
}
/* Draw a line on the screen, specified by its endpoints. In addition, we */
/* have specified a skip factor, which allows us to draw dashed lines. */
void DrawDash(x1, y1, x2, y2, skip)
int x1, y1, x2, y2, skip;
{
int x = x1, y = y1, xadd, yadd, yinc, xabs, yabs, i, j = 0;
if (skip < 0)
skip = 0;
#ifdef ISG
if (!gi.fFile)
{
if (!skip)
{
#ifdef X11
/* For non-dashed X window lines, let's have the Xlib do it for us. */
XDrawLine(gi.disp, gi.pmap, gi.gc, x1, y1, x2, y2);
#endif
#ifdef PCG
/* For non-dashed lines, let's have the graphics library do it for us. */
PcMoveTo(gi.xOffset + x1, gi.yOffset + y1);
PcLineTo(gi.xOffset + x2, gi.yOffset + y2);
#endif
#ifdef AMIGA
{
UWORD mask= 0; /* 16 bit dash mask */
int i,j;
/* taken from the code below... */
for(i= j= 0; i<16; i++)
{
if(j<1) mask |= (1<<i);
j= (j < skip) ? j+1 : 0;
}
SetDrPt(gi.rp, mask);
}
Move(gi.rp, gi.xOffset+x1,gi.yOffset+y1);
Draw(gi.rp, gi.xOffset+x2,gi.yOffset+y2);
SetDrPt(gi.rp, 0xFFFF);
#endif
return;
}
}
#endif /* ISG */
#ifdef PS
if (gs.fPS)
{
/* For PostScript charts we can save file size if we output a LineTo */
/* command when the start vertex is the same as the end vertex of the */
/* previous line drawn, instead of writing out both vertices. */
PsLineCap(fTrue);
PsDash(skip);
if (gi.xPen != x1 || gi.yPen != y1)
fprintf(gi.file, "%d %d %d %d l\n", x1, y1, x2, y2);
else
fprintf(gi.file, "%d %d t\n", x2, y2);
gi.xPen = x2; gi.yPen = y2;
PsStroke(2);
return;
}
#endif
#ifdef META
if (gs.fMeta)
{
/* For metafile charts we can really save file size for consecutive */
/* lines sharing endpoints by consolidating them into a PolyLine. */
if (gi.xPen != x1 || gi.yPen != y1)
{
gi.kiLineDes = (gi.kiLineDes & 15) + 16*(skip > 3 ? 3 : skip);
MetaSelect();
gi.pwPoly = gi.pwMetaCur;
MetaRecord(8, 0x325); /* Polyline */
MetaWord(2); MetaWord(x1); MetaWord(y1);
}
else
{
*gi.pwPoly += 2;
(*(gi.pwPoly+3))++;
/* Note: We should technically update the max record size in the */
/* file header if need be here too, but it doesn't seem necessary. */
}
MetaWord(x2); MetaWord(y2);
gi.xPen = x2; gi.yPen = y2;
return;
}
#endif
/* If none of the above cases hold, we have to draw the line dot by dot. */
xadd = x2 - x1 >= 0 ? 1 : 3;
yadd = y2 - y1 >= 0 ? 2 : 4;
xabs = abs(x2 - x1);
yabs = abs(y2 - y1);
/* Technically what we're doing here is drawing a line which is more */
/* horizontal then vertical. We always increment x by 1, and increment */
/* y whenever a fractional variable passes a certain amount. For lines */
/* that are more vertical than horizontal, we just swap x and y coords. */
if (xabs < yabs)
{
SwapN(xadd, yadd);
SwapN(xabs, yabs);
}
yinc = (xabs >> 1) - ((xabs & 1 ^ 1) && xadd > 2);
for (i = xabs + 1; i; i--)
{
if (j < 1)
DrawPoint(x, y);
j = j < skip ? j+1 : 0;
switch (xadd) {
case 1: x++; break;
case 2: y++; break;
case 3: x--; break;
case 4: y--; break;
}
yinc += yabs;
if (yinc - xabs >= 0)
{
yinc -= xabs;
switch (yadd) {
case 1: x++; break;
case 2: y++; break;
case 3: x--; break;
case 4: y--; break;
}
}
}
}
/* Draw a normal line on the screen; however, if the x coordinates are close */
/* to either of the two given bounds, then we assume that the line runs off */
/* one side and reappears on the other, so draw the appropriate two lines */
/* instead. This is used by the Ley line and astro-graph routines, which */
/* draw lines running around the world and hence off the edges of the maps. */
void DrawWrap(x1, y1, x2, y2, xmin, xmax)
int x1, y1, x2, y2, xmin, xmax;
{
int xmid, ymid, i;
if (x1 < 0) { /* Special case for drawing world map. */
DrawPoint(x2, y2);
return;
}
xmid = (xmax-xmin) / 2;
/* If endpoints aren't near opposite edges, just draw the line and return. */
if (abs(x2-x1) < xmid) {
DrawLine(x1, y1, x2, y2);
return;
}
if ((i = (xmax-xmin+1) + (x1 < xmid ? x1-x2 : x2-x1)) == 0)
i = 1;
/* Determine vertical coordinate where our line runs off edges of screen. */
ymid = y1+(int)((real)(y2-y1)*(x1 < xmid ? (real)(x1-xmin) : (real)(xmax-x1))/(real)i + rRound);
DrawLine(x1, y1, x1 < xmid ? xmin : xmax, ymid);
DrawLine(x2 < xmid ? xmin : xmax, ymid, x2, y2);
}
/* This routine, and its companion below, clips a line defined by its */
/* endpoints to either above some line y=c, or below some line y=c. By */
/* passing in parameters in different orders, we can clip to vertical */
/* lines, too. These are used by the DrawClip() routine below. */
void ClipLesser(x1, y1, x2, y2, s)
int *x1, *y1, *x2, *y2, s;
{
*x1 -= (int)((long)(*y1-s)*(*x2-*x1)/(*y2-*y1));
*y1 = s;
}
void ClipGreater(x1, y1, x2, y2, s)
int *x1, *y1, *x2, *y2, s;
{
*x1 += (int)((long)(s-*y1)*(*x2-*x1)/(*y2-*y1));
*y1 = s;
}
/* Draw a line on the screen. This is just like DrawLine() routine earlier; */
/* however, first clip the endpoints to the given viewport before drawing. */
void DrawClip(x1, y1, x2, y2, xl, yl, xh, yh, skip)
int x1, y1, x2, y2, xl, yl, xh, yh, skip;
{
if (x1 < xl) ClipLesser (&y1, &x1, &y2, &x2, xl); /* Check left side of window. */
if (x2 < xl) ClipLesser (&y2, &x2, &y1, &x1, xl);
if (y1 < yl) ClipLesser (&x1, &y1, &x2, &y2, yl); /* Check top side of window. */
if (y2 < yl) ClipLesser (&x2, &y2, &x1, &y1, yl);
if (x1 > xh) ClipGreater(&y1, &x1, &y2, &x2, xh); /* Check right of window. */
if (x2 > xh) ClipGreater(&y2, &x2, &y1, &x1, xh);
if (y1 > yh) ClipGreater(&x1, &y1, &x2, &y2, yh); /* Check bottom of window. */
if (y2 > yh) ClipGreater(&x2, &y2, &x1, &y1, yh);
DrawDash(x1, y1, x2, y2, skip); /* Go draw the line. */
}
/* Draw a circle or ellipse inside the given bounding rectangle. */
void DrawEllipse(x1, y1, x2, y2)
int x1, y1, x2, y2;
{
int x, y, rx, ry, m, n, u, v, i;
if (gi.fFile)
{
x = (x1+x2)/2; y = (y1+y2)/2; rx = (x2-x1)/2; ry = (y2-y1)/2;
if(gs.fBitmap)
{
m = x + rx; n = y;
for (i = 0; i <= nDegMax; i += DEGINC)
{
u = x + (int)(((real)rx+rRound)*RCosD((real)i));
v = y + (int)(((real)ry+rRound)*RSinD((real)i));
DrawLine(m, n, u, v);
m = u; n = v;
}
}
#ifdef PS
else if (gs.fPS)
{
PsLineCap(fFalse);
PsStrokeForce();
PsDash(0);
fprintf(gi.file, "%d %d %d %d el\n", rx, ry, x, y);
}
#endif
#ifdef META
else
{
gi.kiFillDes = kNull; /* Specify a hollow fill brush. */
MetaSelect();
MetaEllipse(x1+gi.nPenWid/3, y1+gi.nPenWid/3, x2+gi.nPenWid/3, y2+gi.nPenWid/3);
}
#endif
}
#ifdef X11
else
XDrawArc(gi.disp, gi.pmap, gi.gc, x1, y1, x2-x1, y2-y1, 0, nDegMax*64);
#endif
#ifdef MSG
else
_ellipse(_GBORDER, gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
#endif
#ifdef BGI
else
ellipse(gi.xOffset + (x1+x2)/2, gi.yOffset + (y1+y2)/2, 0, 360, (x2-x1)/2, (y2-y1)/2);
#endif
#ifdef AMIGA
else
AmigaDrawEllipse(gi.rp, gi.xOffset + (x1+x2)/2, gi.yOffset + (y1+y2)/2, (x2-x1)/2, (y2-y1)/2);
#endif
}
/* Print a string of text on the graphic window at specified location. To */
/* do this we either use Astrolog's own "font" (6x10) and draw each letter */
/* separately, or else specify system fonts for PostScript and metafiles. */
void DrawSz(sz, x, y, dt)
CONST char *sz;
int x, y, dt;
{
int s = gi.nScale, c = gi.kiCur, cch;
cch = CchSz(sz);
if (!(dt & dtScale))
gi.nScale = gi.nScaleT;
x += gi.nScale;
if (!(dt & dtLeft))
x -= cch*xFont*gi.nScale/2;
if (dt & dtBottom) y -= (yFont-3)*gi.nScale;
else if (!(dt & dtTop)) y -= yFont*gi.nScale/2;
if (dt & dtErase)
{
DrawColor(gi.kiOff);
DrawBlock(x, y, x+xFont*gi.nScale*cch-1, y+(yFont-2)*gi.nScale);
}
DrawColor(c);
#ifdef PS
if (gs.fPS && gs.fFont)
{
PsFont(4);
fprintf(gi.file, "%d %d(%s)center\n", x + xFont*gi.nScale*cch/2, y + yFont*gi.nScale/2, sz);
gi.nScale = s;
return;
}
#endif
while (*sz)
{
#ifdef META
if (gs.fMeta && gs.fFont)
{
gi.nFontDes = 3;
gi.kiTextDes = gi.kiCur;
gi.nAlignDes = 0x6 | 0 /* Center | Top */;
MetaSelect();
MetaTextOut(x, y, 1);
MetaWord(WFromBB(*sz, 0));
}
else
#endif
DrawTurtle(szDrawCh[(_char)*sz-' '], x, y);
x += xFont*gi.nScale;
sz++;
}
gi.nScale = s;
}
/* Draw the glyph of a sign at particular coordinates on the screen. */
/* To do this we either use Astrolog's turtle vector representation or */
/* we may specify a system font character for PostScript and metafiles. */
void DrawSign(i, x, y)
int i, x, y;
{
#ifdef PS
if (gs.fPS && gs.fFont)
{
PsFont(1);
fprintf(gi.file, "%d %d(%c)center\n", x, y, 'A' + i - 1);
return;
}
#endif
#ifdef META
if (gs.fMeta && gs.fFont)
{
gi.nFontDes = 1;
gi.kiTextDes = gi.kiCur;
gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
MetaSelect();
MetaTextOut(x, y+4*gi.nScale, 1);
MetaWord(WFromBB('^' + i - 1, 0));
return;
}
#endif
DrawTurtle(szDrawSign[i], x, y);
}
/* Draw the number of a house at particular coordinates on the screen. */
/* We either use a turtle vector or write a number in a system font. */
void DrawHouse(i, x, y)
int i, x, y;
{
#ifdef PS
if (gs.fPS && gs.fFont)
{
PsFont(3);
fprintf(gi.file, "%d %d(%d)center\n", x, y, i);
return;
}
#endif
#ifdef META
if (gs.fMeta && gs.fFont)
{
gi.nFontDes = 2;
gi.kiTextDes = gi.kiCur;
gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
MetaSelect();
MetaTextOut(x, y+3*gi.nScale, 1 + (i>9));
MetaWord(WFromBB(i > 9 ? '1' : '0'+i, i > 9 ? '0'+i-10 : 0));
return;
}
#endif
DrawTurtle(szDrawHouse[i], x, y);
}
/* Draw the glyph of an object at particular coordinates on the screen. */
void DrawObject(obj, x, y)
int obj, x, y;
{
char szGlyph[4];
if (!gs.fLabel) /* If we are inhibiting labels, then do nothing. */
return;
/* For other planet centered charts, we have to remember that that */
/* particular planet's index now represents the Earth. If we are given */
/* that index to draw, then change it so we draw the Earth instead. */
if (gi.nMode != gOrbit && ((obj == us.objCenter && obj > oMoo) || (us.objCenter == 0 && obj == oSun)))
obj = 0;
DrawColor(kObjB[obj]);
if (obj <= oNorm)
{
#ifdef PS
if (gs.fPS && gs.fFont == 1 && obj < uranLo && szObjectFont[obj] != ' ')
{
PsFont(2);
fprintf(gi.file, "%d %d(%c)center\n", x, y, szObjectFont[obj]);
return;
}
#endif
#ifdef META
if (gs.fMeta && gs.fFont == 1 && obj < uranLo && szObjectFont[obj] != ' ')
{
gi.nFontDes = 4;
gi.kiTextDes = gi.kiCur;
gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
MetaSelect();
MetaTextOut(x, y+5*gi.nScale, 1);
MetaWord(WFromBB(szObjectFont[obj], 0));
return;
}
#endif
DrawTurtle(szDrawObject[obj], x, y);
/* Normally we can just go draw the glyph; however, stars don't have */
/* glyphs, so for these draw their three letter abbreviation. */
}
else /* obj > oNorm */
{
sprintf(szGlyph, "%c%c%c", chObj3(obj));
DrawSz(szGlyph, x, y, dtCent);
}
}
/* Draw the glyph of an aspect at particular coordinates on the screen. */
/* Again we either use Astrolog's turtle vector or a system Astro font. */
void DrawAspect(asp, x, y)
int asp, x, y;
{
CONST char *sz;
#ifdef PS
if (gs.fPS && gs.fFont == 1 && szAspectFont[asp-1] != ' ')
{
PsFont(2);
fprintf(gi.file, "%d %d(%s%c)center\n", x, y,
asp == aSSq || asp == aSes ? "\\" : "", szAspectFont[asp-1]);
return;
}
#endif
#ifdef META
if (gs.fMeta && gs.fFont == 1 && szAspectFont[asp-1] != ' ')
{
gi.nFontDes = 4;
gi.kiTextDes = gi.kiCur;
gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
MetaSelect();
MetaTextOut(x, y+5*gi.nScale, 1);
MetaWord(WFromBB(szAspectFont[asp-1], 0));
return;
}
#endif
sz = szDrawAspect[asp];
if (us.fParallel)
{
if (asp == aCon)
sz = "BU4BLD8BR2U8";
else if (asp = aOpp)
sz = "BU4BLD8BR2U8BF3BLL6BD2R6";
}
DrawTurtle(sz, x, y);
}
/* Convert a string segment to a positive number, updating the string to */
/* point beyond the number chars. Return 1 if the string doesn't point to */
/* a numeric value. This is used by the DrawTurtle() routine to extract */
/* motion vector quantities from draw strings, e.g. the "12" in "U12". */
#if 0
int NFromPch(str)
CONST char **str;
{
int num = 0, i = 0;
loop
{
if (**str < '0' || **str > '9')
return num > 0 ? num : (i < 1 ? 1 : 0);
num = num*10 + (**str)-'0';
(*str)++;
i++;
}
}
#else /* slightly improved version by Tobias Ferber, <tf@antares.ping.de> */
int NFromPch(str)
CONST char **str;
{
register int num = 0, i = 0;
register char *s= (char *)*str;
loop
{
if (*s < '0' || *s > '9')
{
*str= s;
return (num > 0) ? num : ((i < 1) ? 1 : 0);
}
num = num*10 + (*s)-'0';
++s;
++i;
}
}
#endif
/* This routine is used to draw complicated objects composed of lots of line */
/* segments on the screen, such as all the glyphs and coastline pieces. It */
/* is passed in a string of commands defining what to draw in relative */
/* coordinates. This is a copy of the format of the BASIC draw command found */
/* in PC's. For example, "U5R10D5L10" means go up 5 dots, right 10, down 5, */
/* and left 10 - draw a box twice as wide as it is high. */
void DrawTurtle(sz, x0, y0)
CONST char *sz;
int x0, y0;
{
register int i, j, x, y, deltax, deltay;
bool fBlank, fNoupdate;
char chCmd;
gi.xTurtle = x0; gi.yTurtle = y0;
while (chCmd = ChCap(*sz))
{
sz++;
/* 'B' prefixing a command means just move the cursor, and don't draw. */
if( (fBlank = (chCmd == 'B')) )
{
chCmd = ChCap(*sz);
sz++;
}
/* 'N' prefixing a command means don't update cursor when done drawing. */
if( (fNoupdate = (chCmd == 'N')) )
{
chCmd = ChCap(*sz);
sz++;
}
/* Here we process the eight directional commands. */
switch (chCmd) {
case 'U': deltax = 0; deltay = -1; break; /* Up */
case 'D': deltax = 0; deltay = 1; break; /* Down */
case 'L': deltax = -1; deltay = 0; break; /* Left */
case 'R': deltax = 1; deltay = 0; break; /* Right */
case 'E': deltax = 1; deltay = -1; break; /* NorthEast */
case 'F': deltax = 1; deltay = 1; break; /* SouthEast */
case 'G': deltax = -1; deltay = 1; break; /* SouthWest */
case 'H': deltax = -1; deltay = -1; break; /* NorthWest */
default: PrintError("Bad draw."); /* Shouldn't happen. */
}
x = gi.xTurtle;
y = gi.yTurtle;
j = NFromPch(&sz)*gi.nScale; /* Figure out how far to draw. */
if(fBlank)
{
gi.xTurtle += deltax*j;
gi.yTurtle += deltay*j;
}
else
{
if (gs.fPS || gs.fMeta)
{
gi.xTurtle += deltax*j;
gi.yTurtle += deltay*j;
DrawLine(x, y, gi.xTurtle, gi.yTurtle);
}
else
{
DrawPoint(gi.xTurtle, gi.yTurtle);
for (i = 0; i < j; i++)
{
gi.xTurtle += deltax;
gi.yTurtle += deltay;
DrawPoint(gi.xTurtle, gi.yTurtle);
}
}
if (fNoupdate)
{
gi.xTurtle = x;
gi.yTurtle = y;
}
}
}
}
#endif /* GRAPH */
/* xgeneral.c */